package com.dz.scrm.utils

import com.liulishuo.okdownload.DownloadTask
import com.liulishuo.okdownload.OkDownload
import com.liulishuo.okdownload.core.Util
import com.liulishuo.okdownload.core.cause.EndCause
import com.liulishuo.okdownload.kotlin.enqueue4WithSpeed
import java.io.File
import java.util.*
import kotlin.math.ln
import kotlin.math.pow

/**
 * 作者：fanda
 * 时间：2020/8/14 15:42
 * 描述：下载工具类，单例
 */
object DownLoadHelper {

    const val TAG = "DownLoadHelper"
    private var mDownLoadCallBack: DownLoadCallBack? = null
    private var mSingleTaskSavePath = ""
    private var task: DownloadTask? = null
    private var taskId: Int = -1

    /**
     * 作者：fanda
     * 描述：开始单任务下载，默认重新下载，不断点下载
     */
    @JvmStatic
    fun startSingleTask(url: String, savePath: String,needBreakPoint: Boolean =false, callBack: DownLoadCallBack) {
        this.mSingleTaskSavePath = savePath
        mDownLoadCallBack = callBack
        task = DownloadTask.Builder(url, File(savePath)).setMinIntervalMillisCallbackProcess(400)
                .setConnectionCount(1).setReadBufferSize(8192).setFlushBufferSize(32768).build()
        taskId = task?.id ?: -1
        startDownload(needBreakPoint)
    }

    /**
     * 作者：fanda
     * 描述：断点下载为继续下载，不断点下载就是重新下载
     */
    @JvmStatic
    fun startDownload(needBreakPoint: Boolean) {
        if (!needBreakPoint && taskId != -1) {
            // 去除断点下载信息
            OkDownload.with().breakpointStore().remove(taskId)
            deleteDownloadFile()
        }
        var totalLength: Long = 0
        var readableTotalLength: String? = null
        task?.enqueue4WithSpeed(
                onInfoReadyWithSpeed = { _, info, _, _ ->
                    totalLength = info.totalLength
                    // 这是下载总大小，给用户看的
                    readableTotalLength = Util.humanReadableBytes(totalLength, true)
                    LoggerUtils.d("下载准备好了...当前进度 -> ${info.totalOffset} ==== 总进度 -> $totalLength")
                    mDownLoadCallBack?.onDownLoadReady(info.totalOffset, totalLength)
                },
                onProgressWithSpeed = { _, currentOffset, taskSpeed ->
                    LoggerUtils.d("下载中....当前进度 -> $currentOffset ==== 速度 -> ${taskSpeed.speed()}")
                    mDownLoadCallBack?.onDownLoading(currentOffset, totalLength, taskSpeed.speed())
                }
        ) { task, cause, realCause, taskSpeed ->
            when (cause) {
                EndCause.COMPLETED -> {
                    LoggerUtils.d("下载完成....文件存储路径为 -> " + task.file!!.absolutePath)
                    mDownLoadCallBack?.onDownLoadComplete(task.file!!.absolutePath)
                }
                EndCause.ERROR -> {
                    LoggerUtils.d("下载失败...." + realCause.toString())
                    var tips = ""
                    realCause?.let { tips = it.toString() }
                    mDownLoadCallBack?.onDownLoadFail(cause.toString(), tips, taskSpeed.averageSpeed())
                }
                else -> {
                }
            }
        }
    }

    /**
     * 作者：fanda
     * 时间：2020/8/14 17:41
     * 描述：取消下载
     */
    @JvmStatic
    fun cancelDownload() {
        task?.cancel()
    }

    /**
     * 作者：fanda
     * 描述：移除下载回调
     */
    @JvmStatic
    fun removeDownLoadCallBack() {
        if (mDownLoadCallBack != null) {
            mDownLoadCallBack = null
        }
    }

    /**
     * 作者：fanda
     * 描述：删除下载文件
     */
    @JvmStatic
    fun deleteDownloadFile() {
        if (mSingleTaskSavePath.isNotEmpty()) {
            val result = FileDirUtils.deleteFile(File(mSingleTaskSavePath))
            LoggerUtils.d("文件删除成功....$mSingleTaskSavePath")
        }
    }
}

/**
 * 作者：fanda
 * 描述：接口回调接口实现
 */
open class DefaultDownLoadCallBack : DownLoadCallBack {

    override fun onDownLoadReady(offset: Long, total: Long) {}

    override fun onDownLoadComplete(savePath: String) {}

    override fun onDownLoadFail(state: String, errorMsg: String, speed: String) {}

    override fun onDownLoading(offset: Long, total: Long, speed: String) {}

}

/*接口回调*/
interface DownLoadCallBack {
    fun onDownLoadReady(offset: Long, total: Long)
    fun onDownLoadComplete(savePath: String)
    fun onDownLoadFail(state: String, errorMsg: String, speed: String)
    fun onDownLoading(offset: Long, total: Long, speed: String)
}

/**
 * @param si whether using SI unit refer to International System of Units.
 */
fun humanReadableBytes(bytes: Long, si: Boolean): String? {
    val unit = if (si) 1000 else 1024
    if (bytes < unit) return "$bytes B"
    val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
    val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1].toString() + if (si) "" else "i"
    return String.format(Locale.ENGLISH, "%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
}